# file:: logic.rb
# author::  Ralph M. Churchill
# version::
# date::
#
# This source code copyright (C) 2006 by Ralph M. Churchill
# All rights reserved.
#
# Released under the terms of the GNU General Public License
# See LICENSE file for additional information.

require 'models/container'

# Logic Function "API"
    # do_init: called when Logic created, allows for Logic initialization
    # do_added: called when Logic is added to @entity
    # do_removed: called when Logic is removed from @entity
    # do_logic: called when Logic is invoked
# Logic Assembly "API"
    # invoked_by
    # needs_data
    # optionally
    # saveable
    # applicable_to
    # applied_message
    # removed_message
class Logic
    include BelongsToEntity #, Observable
    properties :action_type,:action_performer

    def self.metaclass
        class << self
            self
        end
    end

    # [+arr+] a list of Action types (as symbols)
    # that can invoke this logic. Use wildcard, :*,
    # to specify all.
    def self.invoked_by(*arr)
        class_eval do
            define_method :invokers do
                empty_array = []
                if arr[0] == :* then
                    class << empty_array
                        def include?(v)
                            true
                        end
                    end
                    empty_array
                else
                    arr || []
                end
            end
        end
    end
    def self.needs_data(*arr)
        properties *arr
        class_eval do
            define_method :needed_data do
                arr || []
            end
        end
    end
    def self.optionally(*arr)
        properties *arr
        class_eval do
            define_method :optional_data do
                arr || []
            end
        end
    end
    def self.saveable
        class_eval do
            define_method :save do
                true
            end
            define_method :save? do
                true
            end
        end
    end
    def self.stackable(rule=:exclusive)
        raise "#{rule} is not a valid stacking rule" unless \
            [:exclusive,:replaceable,:stackable].include?(rule)
        class_eval do
            instance_variable_set("@stacking_rule", rule)
        end
    end
    def stacking_rule
        self.class.instance_variable_get("@stacking_rule") || :exclusive
    end
    def self.applied_message(msg)
        class_eval do 
            define_method :applied do
                msg
            end
        end
    end
    def self.removed_message(msg)
        class_eval do 
            define_method :removed do
                msg
            end
        end
    end
    # This method defines the constructor.
    def self.applicable_to(*valid_for)
        class_eval do
            define_method :initialize do |owner|
                raise "#{owner.class} not support by this Logic" unless \
                    valid_for.include?(owner.class)
                self.owner = owner
                do_init
            end
        end
    end

    # -------------------------------------------------------------------------
    # Core Method
    # -------------------------------------------------------------------------
    def do_action(action)
        return true unless invokers.include?(action.type)
        
        self.action_type = action.type
        self.action_performer = action.performer

        needed_data.each do |k|
            d = action.data[k]
            raise "Missing required data \"#{k}\"." unless d
            self.send("#{k}=",d)
        end if respond_to?(:needed_data)

        optional_data.each do |k|
            d = action.data[k]
            self.send("#{k}=",d)
        end if respond_to?(:optional_data)

        result = do_logic

        # cleanup
        result
    end

    # -------------------------------------------------------------------------
    # Callbacks
    # -------------------------------------------------------------------------
    def do_init; end
    def do_added; end
    def do_removed; end
    def do_logic
        raise NoMethodError("\"do_logic\" not implemented!")
    end


end
